﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Inscriptionem.Areas.Inscriptionem.Models.Enums;
using Inscriptionem.Areas.Inscriptionem.Models.Requests;
using Inscriptionem.Areas.Inscriptionem.Models.Views;
using Inscriptionem.Authorization;
using Inscriptionem.Extensions;

namespace Inscriptionem.Areas.Inscriptionem.Controllers
{
    [InscriptionemAuthorize(MemberRole.Admin)]
    public class CategoryController : Controller
    {
        private readonly ORM.DB DB;
        public CategoryController()
        {
            DB = new ORM.DB();
        }

        public ActionResult Index()
        {
            return View("Index", new CategoryCollectionViewModel());
        }

        [HttpPost]
        public ActionResult Add(CategoryRequestModel model)
        {
            var result = new CategoryViewModel();
            model.CopyTo(result);

            result.Error = ValidateCategoryAddModel(result);

            if (result.Error == CategoryError.None)
            {
                try
                {
                    var category = new ORM.Category()
                    {
                        Name = result.Name.Trim(),
                        Order = result.Order,
                        Section = DB.Sections.First(s => s.ID == model.Section),
                        CreatedDate = DateTime.Now,
                        ModifiedDate = DateTime.Now
                    };

                    DB.AddToCategories(category);
                    DB.SaveChanges();
                }
                catch (Exception)
                {
                    result.Error = CategoryError.Other;
                }
            }

            if (result.Error == CategoryError.None)
            {
                return RedirectToAction("Index");
            }

            return View("Add", result);
        }

        [HttpPost]
        public ActionResult Edit(CategoryRequestModel model)
        {
            var result = new CategoryViewModel();
            model.CopyTo(result);

            // Not the best way to check if "Edit" button was pressed
            if (result.ID > 0 && string.IsNullOrWhiteSpace(result.Name))
            {
                var category = DB.Categories.FirstOrDefault(c => c.ID == result.ID);
                if (category == null)
                {
                    // Category not found
                    return RedirectToAction("Index");
                }

                result.Order = category.Order;
                result.Name = category.Name;
                result.Section = category.Section.ID;

                return View("Edit", result);
            }

            // Validate
            result.Error = ValidateCategoryEditModel(result);
            if (result.Error == CategoryError.None)
            {
                // Save changes
                try
                {
                    var category = DB.Categories.FirstOrDefault(c => c.ID == result.ID);

                    if (category == null)
                    {
                        return RedirectToAction("Index");
                    }

                    category.Order = result.Order;
                    category.Name = result.Name.Trim();
                    category.Section = DB.Sections.First(s => s.ID == result.Section);
                    category.ModifiedDate = DateTime.Now;

                    DB.SaveChanges();

                    return RedirectToAction("Index");
                }
                catch (Exception)
                {
                    result.Error = CategoryError.Other;
                }
            }

            return View("Edit", result);
        }

        [HttpPost]
        public ActionResult Delete(int ID)
        {
            if (ID <= 0)
            {
                return RedirectToAction("Index");
            }

            var category = DB.Categories.FirstOrDefault(c => c.ID == ID);
            if (category == null)
            {
                return RedirectToAction("Index");
            }

            CategoryError result = CategoryError.None;

            try
            {
                if (category.PostCategories.Any())
                {
                    result = CategoryError.CategoryHasContent;
                }
                else
                {
                    DB.Categories.DeleteObject(category);
                    DB.SaveChanges();

                    return RedirectToAction("Index");
                }
            }
            catch (Exception)
            {
                result = CategoryError.Other;
            }

            return View("Delete", result);
        }

        public ActionResult Order()
        {
            return View("Order", new CategoryCollectionViewModel());
        }

        [HttpPost]
        public ActionResult Order(IList<CategoryOrderRequestModel> categories)
        {
            var error = ValidateCategoryOrderModel(categories);
            if (error == OrderError.None)
            {
                // Save
                foreach (var category in categories)
                {
                    var dbCategory = DB.Categories.FirstOrDefault(c => c.ID == category.ID);
                    if (dbCategory != null)
                    {
                        dbCategory.Order = category.Order;
                        dbCategory.ModifiedDate = DateTime.Now;
                    }
                }

                DB.SaveChanges();
            }

            return View("Order", new CategoryCollectionViewModel() { Error = error });
        }

        #region Implementation
        private OrderError ValidateCategoryOrderModel(IList<CategoryOrderRequestModel> Categories)
        {
            if (Categories == null || Categories.Count == 0)
            {
                return OrderError.Other;
            }

            if (Categories.Any(c => c.Order <= 0))
            {
                return OrderError.OrderNotValid;
            }

            var lookup = Categories.ToLookup(c => c.Section);

            foreach (var group in lookup)
            {
                var list = new List<int>();

                foreach (var category in group)
                {
                    if (!list.Contains(category.Order))
                    {
                        list.Add(category.Order);
                    }
                    else
                    {
                        return OrderError.OrderDuplicate;
                    }
                }
            }

            return OrderError.None;
        }

        private CategoryError ValidateCategoryAddModel(CategoryViewModel Model)
        {
            var editValidateResult = ValidateCategoryEditModel(Model);
            if (editValidateResult != CategoryError.None)
            {
                return editValidateResult;
            }

            var language = DB.Sections.First(s => s.ID == Model.Section).Categories.FirstOrDefault(c => c.Name.ToLower() == Model.Name.ToLower().Trim());
            if (language != null)
            {
                return CategoryError.CategoryAlreadyExists;
            }

            return CategoryError.None;
        }

        private CategoryError ValidateCategoryEditModel(CategoryViewModel Model)
        {
            if (string.IsNullOrWhiteSpace(Model.Name))
            {
                return CategoryError.CategoryEmpty;
            }

            if (Model.Section <= 0 || DB.Sections.FirstOrDefault(s => s.ID == Model.Section) == null)
            {
                return CategoryError.CategorySectionEmpty;
            }

            if (Model.Order <= 0)
            {
                return CategoryError.OrderNotValid;
            }

            var category = DB.Sections.First(s => s.ID == Model.Section).Categories.FirstOrDefault(c => c.Order == Model.Order);
            if (category != null && category.ID != Model.ID)
            {
                return CategoryError.OrderAlreadyInUse;
            }

            return CategoryError.None;
        }
        #endregion
    }
}
